package com.boat.starter.springdoc;

import org.springdoc.core.GroupedOpenApi;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.core.env.Environment;

import com.boat.starter.springdoc.constant.DocConsts;
import com.boat.starter.springdoc.filter.OpenapiJsonInterceptor;
import com.boat.starter.springdoc.props.DocProperties;

import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.servers.Server;
import lombok.extern.slf4j.Slf4j;

/**
 * spring doc自动装配
 * 为了安全考虑，只在开发环境和测试环境生效，生产环境不生效
 * @author 周江
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(DocProperties.class)
@ConditionalOnProperty(prefix = DocConsts.PREFIX, value = "type", havingValue = DocConsts.DocType.SPRINGDOC)
public class SpringDocAutoConfiguration implements InitializingBean{

	@Bean
	@ConditionalOnProperty(name = DocConsts.SPRINGDOC_ENABLE, havingValue = "true", matchIfMissing = true)
	public OpenAPI springShopOpenApi(DocProperties docProperties, Environment environment) {
		OpenAPI openApi = new OpenAPI();
		
		//设置info参数
		openApi.info(createInfo(docProperties, environment));
		
		//设置host参数
		if(StrUtil.isNotBlank(docProperties.getSpringdoc().getHost())) {
			Server serverItem = new Server();
			serverItem.setUrl(docProperties.getSpringdoc().getHost());
			openApi.addServersItem(serverItem);
		}
		
		return openApi;
	}

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnProperty(name = DocConsts.SPRINGDOC_ENABLE, havingValue = "true", matchIfMissing = true)
	public GroupedOpenApi defaultGroupApi(DocProperties docProperties, Environment environment) {
		return GroupedOpenApi.builder().group("default").pathsToMatch("/**").pathsToExclude("/error").build();
	}

	/**
	 * 使用拦截器修正Knife4j不显示basePath参数问题
	 * 注：因swagger3已去除basePath参数，但是根据明心实际情况，需要这个参数
	 * @param docProperties
	 * @return
	 */
	@Bean
	@ConditionalOnProperty(name = DocConsts.SPRINGDOC_ENABLE, havingValue = "true", matchIfMissing = true)
	public OpenapiJsonInterceptor openapiJsonInterceptor(DocProperties docProperties) {
		return new OpenapiJsonInterceptor(docProperties);
	}

	private Info createInfo(DocProperties docProperties, Environment environment) {
		// 获得title
		String title = docProperties.getSpringdoc().getTitle();
		if (StrUtil.isBlankIfStr(title)) {
			title = environment.getProperty("info.title");
		}
		if (StrUtil.isBlankIfStr(title)) {
			title = environment.getProperty("spring.application.name");
		}

		// 获得description
		String description = docProperties.getSpringdoc().getDescription();
		if (StrUtil.isBlankIfStr(description)) {
			description = environment.getProperty("info.description");
		}
		if (StrUtil.isBlankIfStr(description)) {
			description = DocConsts.INFO_DESCRIPTION;
		}

		// 获得version
		String version = docProperties.getSpringdoc().getVersion();
		if (StrUtil.isBlankIfStr(version)) {
			version = environment.getProperty("info.version");
		}
		if (StrUtil.isBlankIfStr(version)) {
			version = DocConsts.INFO_VERSION;
		}

		return new Info().title(title).description(description).version(version);
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		log.info("boat-starter-springdoc加载成功");
	}
}
